x86: No need to take full reference when doing mmu_update on a foreign
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 1 Mar 2007 12:14:53 +0000 (12:14 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 1 Mar 2007 12:14:53 +0000 (12:14 +0000)
domain. Also fix a pre-existing race setting PGT_pinned versus
clearing it during domain_kill().
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/mm.c
xen/include/xen/sched.h

index 10f5a86b4dd4fa2b9e51e70caec668c988fc1b0d..d7cd0420864f151f2a024ff00520dfad1a0e0588 100644 (file)
@@ -1853,7 +1853,7 @@ static void process_deferred_ops(void)
 
     if ( unlikely(info->foreign != NULL) )
     {
-        put_domain(info->foreign);
+        rcu_unlock_domain(info->foreign);
         info->foreign = NULL;
     }
 }
@@ -1885,8 +1885,7 @@ static int set_foreigndom(domid_t domid)
         switch ( domid )
         {
         case DOMID_IO:
-            get_knownalive_domain(dom_io);
-            info->foreign = dom_io;
+            info->foreign = rcu_lock_domain(dom_io);
             break;
         default:
             MEM_LOG("Dom %u cannot set foreign dom", d->domain_id);
@@ -1896,18 +1895,16 @@ static int set_foreigndom(domid_t domid)
     }
     else
     {
-        info->foreign = e = get_domain_by_id(domid);
+        info->foreign = e = rcu_lock_domain_by_id(domid);
         if ( e == NULL )
         {
             switch ( domid )
             {
             case DOMID_XEN:
-                get_knownalive_domain(dom_xen);
-                info->foreign = dom_xen;
+                info->foreign = rcu_lock_domain(dom_xen);
                 break;
             case DOMID_IO:
-                get_knownalive_domain(dom_io);
-                info->foreign = dom_io;
+                info->foreign = rcu_lock_domain(dom_io);
                 break;
             default:
                 MEM_LOG("Unknown domain '%u'", domid);
@@ -2043,6 +2040,12 @@ int do_mmuext_op(
             /* A page is dirtied when its pin status is set. */
             mark_dirty(d, mfn);
            
+            /* We can race domain destruction (domain_relinquish_resources). */
+            if ( unlikely(this_cpu(percpu_mm_info).foreign != NULL) &&
+                 test_bit(_DOMF_dying, &FOREIGNDOM->domain_flags) &&
+                 test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
+                put_page_and_type(page);
+
             break;
 
         case MMUEXT_UNPIN_TABLE:
index cbfb67a9e796ea5df3590baaf91689e8711d4686..0ab2874129a5e2160c164ea902ac168400d982ac 100644 (file)
@@ -292,10 +292,15 @@ static inline void rcu_unlock_domain(struct domain *d)
     rcu_read_unlock(&domlist_read_lock);
 }
 
+static inline struct domain *rcu_lock_domain(struct domain *d)
+{
+    rcu_read_lock(d);
+    return d;
+}
+
 static inline struct domain *rcu_lock_current_domain(void)
 {
-    rcu_read_lock(&domlist_read_lock);
-    return current->domain;
+    return rcu_lock_domain(current->domain);
 }
 
 struct domain *get_domain_by_id(domid_t dom);